Manejo y visualización de datos

Importar, transformar y visualizar datos en R

Manejo de datos

La exploración de datos nos permite verificar su calidad, entender los datos con los que trabajamos. Visualizar nuestros datos es un buen comienzo, pero a menudo vamos a necesitar transformar los datos previamente.

Formato tidy data

Cada variable tiene su propia columna Cada observación tiene su propia fila Cada valor tiene su propia celda

Ejemplo organización “tidy”

Buenas prácticas en el manejo de datos

  • Las variables van en columnas (e.g. mediciones: altura, peso, sexo)
  • Tabla del análisis de la varianza
  • Las observaciones cada una en una fila (e.g. individuos de pingüinos)
  • Evitar espacios, números, y caracteres especiales en los nombres de columnas.
  • Siempre anotar valores de cero, para diferenciarlos de datos faltantes.
  • Usar celdas vacías o con NA para datos faltantes.
  • Las fechas incluirlas en columnas separadas como year, month, day.
  • No combinar varias informaciones en una misma celda. EJEMPLOS
  • Realiza todas las manipulaciones de datos mediante código para dejar constancia de los cambios.
  • Exporta los datos como texto plano (txt, csv)

Organizacion tabla

Hertz & McNeill 2024 ## dplyr y ggplot

coomo funcionan, libreria tidyverse.

Pipes: cómo encadenar operaciones

Los “pipes” permiten escribir código paso a paso, de forma legible:

library(dplyr)

# El propio de dplyr
iris %>%
  filter(Sepal.Length > 5) %>%
  summarise(promedio = mean(Sepal.Width))
  promedio
1 3.048305
# (control  (command) + shift + M)

# el de R desde hace dos años
iris |>
  filter(Sepal.Length > 5) |>
  summarise(promedio = mean(Sepal.Width))
  promedio
1 3.048305

Ejemplo datos de pingüinos

# 1. Cargar librerías

library(dplyr)
library(ggplot2)
library(readr)
library(palmerpenguins)
library(scico)

# 2. Leer datos
data(package = 'palmerpenguins')
datos <- penguins

# 3. Explorar

head(datos)
# A tibble: 6 × 8
  species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
1 Adelie  Torgersen           39.1          18.7               181        3750
2 Adelie  Torgersen           39.5          17.4               186        3800
3 Adelie  Torgersen           40.3          18                 195        3250
4 Adelie  Torgersen           NA            NA                  NA          NA
5 Adelie  Torgersen           36.7          19.3               193        3450
6 Adelie  Torgersen           39.3          20.6               190        3650
# ℹ 2 more variables: sex <fct>, year <int>
str(datos)
tibble [344 × 8] (S3: tbl_df/tbl/data.frame)
 $ species          : Factor w/ 3 levels "Adelie","Chinstrap",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ island           : Factor w/ 3 levels "Biscoe","Dream",..: 3 3 3 3 3 3 3 3 3 3 ...
 $ bill_length_mm   : num [1:344] 39.1 39.5 40.3 NA 36.7 39.3 38.9 39.2 34.1 42 ...
 $ bill_depth_mm    : num [1:344] 18.7 17.4 18 NA 19.3 20.6 17.8 19.6 18.1 20.2 ...
 $ flipper_length_mm: int [1:344] 181 186 195 NA 193 190 181 195 193 190 ...
 $ body_mass_g      : int [1:344] 3750 3800 3250 NA 3450 3650 3625 4675 3475 4250 ...
 $ sex              : Factor w/ 2 levels "female","male": 2 1 1 NA 1 2 1 2 NA NA ...
 $ year             : int [1:344] 2007 2007 2007 2007 2007 2007 2007 2007 2007 2007 ...
summary(datos)
      species          island    bill_length_mm  bill_depth_mm  
 Adelie   :152   Biscoe   :168   Min.   :32.10   Min.   :13.10  
 Chinstrap: 68   Dream    :124   1st Qu.:39.23   1st Qu.:15.60  
 Gentoo   :124   Torgersen: 52   Median :44.45   Median :17.30  
                                 Mean   :43.92   Mean   :17.15  
                                 3rd Qu.:48.50   3rd Qu.:18.70  
                                 Max.   :59.60   Max.   :21.50  
                                 NA's   :2       NA's   :2      
 flipper_length_mm  body_mass_g       sex           year     
 Min.   :172.0     Min.   :2700   female:165   Min.   :2007  
 1st Qu.:190.0     1st Qu.:3550   male  :168   1st Qu.:2007  
 Median :197.0     Median :4050   NA's  : 11   Median :2008  
 Mean   :200.9     Mean   :4202                Mean   :2008  
 3rd Qu.:213.0     3rd Qu.:4750                3rd Qu.:2009  
 Max.   :231.0     Max.   :6300                Max.   :2009  
 NA's   :2         NA's   :2                                 
unique(datos$island)
[1] Torgersen Biscoe    Dream    
Levels: Biscoe Dream Torgersen
datos_filtrados <- datos %>% filter (year == 2007)

datos_filtrados <-datos %>% filter (year == 2007, sex=="female")

datos_filtrados <- datos %>% filter (year == 2007, sex=="female", island %in% c("Dream", "Bicoe")) 
# island == c("Dream", "Bicoe")) NO VALE!
# summarize
head (datos_filtrados, 3)
# A tibble: 3 × 8
  species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>   <fct>           <dbl>         <dbl>             <int>       <int>
1 Adelie  Dream            39.5          16.7               178        3250
2 Adelie  Dream            39.5          17.8               188        3300
3 Adelie  Dream            36.4          17                 195        3325
# ℹ 2 more variables: sex <fct>, year <int>

Limpiar los datos

# 4. Limpiar: eliminar filas con NA
datos_limpios <- datos %>% 
  filter(!is.na(body_mass_g))

head(datos_limpios, 4)
# A tibble: 4 × 8
  species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
1 Adelie  Torgersen           39.1          18.7               181        3750
2 Adelie  Torgersen           39.5          17.4               186        3800
3 Adelie  Torgersen           40.3          18                 195        3250
4 Adelie  Torgersen           36.7          19.3               193        3450
# ℹ 2 more variables: sex <fct>, year <int>

Transformar variables

# 5. Transformar: crear nueva variable
datos_limpios_kg <- datos_limpios %>%
  mutate(body_mass_kg = body_mass_g / 1000)

De simple

ggplot(data = datos_limpios_kg, aes(x = bill_length_mm, y = bill_depth_mm)) + geom_point()

A complejo

library(ggplot2)

p <- ggplot(data = penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
geom_point(aes(color = body_mass_g), alpha = .6) +
  scico::scale_color_scico(palette = "bamako", direction = -1)+ 
## custom axes scaling
scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5), limits = c(12.5, 22.5)) +
## custom labels
labs(
title = 'Bill Dimensions of Brush-Tailed Penguins (Pygoscelis)',
subtitle = 'A scatter plot of bill depth versus bill length.',
caption = 'data = Gorman, Williams & Fraser (2014) PLoS ONE, graph = Cédric Scherer',
x = 'Bill Length (mm)',
y = 'Bill Depth (mm)',
color = 'Body mass (g)'
) + theme_minimal () 
p

Ejemplo datos inscripción curso

library(here)
library(tidyverse)
library(tm)
library(wordcloud2)
library(readxl)

# se puede importar tablas desde excel, csv, ggsheets, txt...

datos_curso = read_excel(here("data/datos-curso.xlsx"))
# ifselse en dplyr?
# Vemos un resumen
str (datos_curso)
tibble [19 × 15] (S3: tbl_df/tbl/data.frame)
 $ Id                                                                    : num [1:19] 1 2 3 4 5 6 7 8 9 10 ...
 $ Hora de inicio                                                        : POSIXct[1:19], format: "2025-10-14 08:29:14" "2025-10-14 08:42:03" ...
 $ Hora de finalización                                                  : POSIXct[1:19], format: "2025-10-14 08:37:19" "2025-10-14 08:44:21" ...
 $ Correo electrónico                                                    : chr [1:19] "anonymous" "anonymous" "anonymous" "anónimo" ...
 $ Nombre                                                                : logi [1:19] NA NA NA NA NA NA ...
 $ Comentarios: DNI o documento                                          : logi [1:19] NA NA NA NA NA NA ...
 $ Curso de la primera matrícula en el programa de doctorado             : chr [1:19] "2024-25" "2023-24" "2022-23" "2023-24" ...
 $ Puntos: Curso de la primera matrícula en el programa de doctorado     : num [1:19] 0 0 0 NA NA NA NA NA NA NA ...
 $ Comentarios: Curso de la primera matrícula en el programa de doctorado: logi [1:19] NA NA NA NA NA NA ...
 $ Cuéntanos tu experiencia con R                                        : chr [1:19] "He usado R ya en anteriores ocasiones, tengo una pequeña base de conocimientos y estoy familiarizada con el lenguaje." "Usé R en el máster y para hacer algunos gráficos durante el principio de la tesis, pero me falta mucha segurida"| __truncated__ "Para mi tesis en el programa he debido desarrollar un Tn-seq, personalmente me ha costado horas de trabajo crea"| __truncated__ "He utilizado R en algunas asignaturas del grado y del máster, pero de una manera superficial." ...
 $ Puntos: Cuéntanos tu experiencia con R                                : num [1:19] 0 0 0 NA NA NA NA NA NA NA ...
 $ Comentarios: Cuéntanos tu experiencia con R                           : logi [1:19] NA NA NA NA NA NA ...
 $ Observaciones                                                         : chr [1:19] NA NA NA NA ...
 $ Puntos: Observaciones                                                 : num [1:19] 0 0 0 NA NA NA NA NA NA NA ...
 $ Comentarios: Observaciones                                            : logi [1:19] NA NA NA NA NA NA ...
#View (datos_curso) # Se nos abre en Rstudio
colnames(datos_curso) # Miramos las columnas que tiene
 [1] "Id"                                                                    
 [2] "Hora de inicio"                                                        
 [3] "Hora de finalización"                                                  
 [4] "Correo electrónico"                                                    
 [5] "Nombre"                                                                
 [6] "Comentarios: DNI o documento"                                          
 [7] "Curso de la primera matrícula en el programa de doctorado"             
 [8] "Puntos: Curso de la primera matrícula en el programa de doctorado"     
 [9] "Comentarios: Curso de la primera matrícula en el programa de doctorado"
[10] "Cuéntanos tu experiencia con R"                                        
[11] "Puntos: Cuéntanos tu experiencia con R"                                
[12] "Comentarios: Cuéntanos tu experiencia con R"                           
[13] "Observaciones"                                                         
[14] "Puntos: Observaciones"                                                 
[15] "Comentarios: Observaciones"                                            
datos_curso_filtrado <- datos_curso |>
  rename (curso = "Curso de la primera matrícula en el programa de doctorado",
         experiencia = "Cuéntanos tu experiencia con R",
         comentarios = "Observaciones",
         email = "Correo electrónico") |>
  select (curso, experiencia, comentarios, email) |>
  mutate (email = str_replace(email, "anonymous", "anónimo")) |>
  filter (curso == "2022-23") # filtrado y sin filtrar otra diapo.
  
words <- tolower(
                unlist(
                  strsplit(datos_curso_filtrado$experiencia, " ") ) ) 

words <- gsub("[[:punct:][:digit:]]", "",words)
stop_es <- stopwords("spanish")
words_clean <- words[!words %in% stop_es]

# Plot
wordcloud2(data=table(words_clean), size=0.5,
           color = rep(RColorBrewer::brewer.pal(11, "PRGn"), 20))

Visualizacion de datos

  • Bases de la visualizacion
  • Base R vs ggplot

Desde gráficos muy simples

plot(x=rnorm(100), y=rnorm(100))

Hasta gráficos muy complejos

quién habla con quién en “The Office” Código

Bases de ggplot

scatterplot

boxplots

ggplot (data = datos_limpios_kg, aes(x = island, y = bill_length_mm)) + geom_boxplot()

violin

xxxx

Colores

Colores… https://www.fabiocrameri.ch/colourmaps/

Mapas I

Mapa del crecimiento urbano en Valencia Código

Mapas II

Apicultores en Alemania Código

Nuestros datos georeferenciados

library(rgbif)
library(ggplot2)
library(rnaturalearth)
library(sf)

datos <- occ_search(scientificName = "Lynx pardinus", limit = 100)
#head(datos$data[, c("species", "decimalLatitude", "decimalLongitude")])
df <- datos$data

# Basic map
world <- ne_countries(scale = "medium", returnclass = "sf")

# Plot
ggplot() +
  geom_sf(data = world, fill = "grey90", color = "grey30") +
  geom_point(data = df, aes(x = decimalLongitude, y = decimalLatitude),
             color = "darkred", size = 2, alpha = 0.7) +
  coord_sf() +
  theme_minimal()
# Basic map
spain <- ne_countries(country=c("spain", "portugal"))
# plot(spain)
# Plot

ggplot() +
  geom_sf(data = spain, fill = "grey99", color = "grey30") +
  geom_point(data = df, aes(x = decimalLongitude, y = decimalLatitude),
             color = "darkgreen", size = 2, alpha = 0.7) +
  coord_sf() +
  theme_minimal()

Mapa plantas

library(FloraIberica)
map_distribution(genus = "Lavandula", species = "stoechas", size = 0.9)

Visualizaciones geniales (ya no solo con r)

Valentina de Filippo

Bibliografía

Valentina de Filippo Eleven quick tips for properly handling tabular data ## Ejercicios